#ifndef __STINGER_H__
#define __STINGER_H__


#include <iostream>
#include <cstring>

#include <unistd.h>
#include <string.h>
#include <assert.h>

#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/p.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/pool.hpp>
#include <libpmemobj++/transaction.hpp>
#include <libpmemobj++/container/string.hpp>
#include <libpmemobj++/container/concurrent_hash_map.hpp>

#include "util.h"

namespace {

    inline int file_exists(char const *file) {
        return access(file, F_OK);
    }
    typedef pmem::obj::p<int> p_int;
    typedef pmem::obj::p<int64_t> p_int64_t;
    typedef pmem::obj::p<long> p_long;
    
    using hashmap = pmem::obj::concurrent_hash_map<pmem::obj::p<int>, pmem::obj::p<int>>;

    const char * PERSIST_FILE_PATH     = "stinger_graph";
    const char * LAYOUT                = "stinger";
    const int    STINGER_EDGEBLOCKSIZE = 4;
    const int    ETYPE_NUM             = 100;                   // 边类型的数量
    const int    VTYPE_NUM             = 100;                   // 顶点类型的数量
    const int    POOLSIZE              = 1024 * 1024 * 256;      // 64 MB的空间
    const int    VERTEX_NAME_SIZE      = 255;                   // 字符串最大长度
    const int    VERTEX_NUM            = 1000;                  // 顶点的数量
    const int    EDGE_NUM_PER_TYPE     = 300;                   // 每种类型的边的最大数量
    
}

//一条边，存储在边块中
struct stinger_edge
{
    p_int neighbor;	        //相邻顶点的ID
    p_int weight;	        //这条边的权重
    p_long timeFirst;	
    p_long timeRecent;
};

//边块，一个边块包含 STINGER_EDGEBLOCKSIZE 条边，设为 16.
struct stinger_eb
{
    pmem::obj::persistent_ptr<stinger_eb> next_edge_block_ptr = nullptr;
    p_int etype;	        // 该边块类型
    p_int vertexID;	        // 该边块的顶点
    p_int numEdges;	        // 该边块中的边的数目(只记录有效边)
    p_int high;		        // High water mark ?????（包括有效边和无效边）
    p_long smallStamp;	    
    p_long largeStamp;	    
    //p_int cache_pad;	    // 无意义，只为了对齐
    struct stinger_edge edges[STINGER_EDGEBLOCKSIZE]; //边的数组
};

//一个顶点
struct stinger_vertex
{
    p_int   id;                         // 物理顶点的ID？Physical Vertex ID
    char    name[VERTEX_NAME_SIZE];     // 名称
    p_int   type;	                    // 顶点类型
    p_int   weight;                     // 顶点权重
    p_int   inDegree;                   // 入度
    p_int   outDegree;                  // 出度
    pmem::obj::persistent_ptr<stinger_eb> edge_block_ptr = nullptr;
    stinger_vertex () {}
    stinger_vertex (int vertex_id, std::string vertex_name, int vertex_type, int vertex_weight, int vertex_in_degree, int vertex_out_degree) {
        id = vertex_id;
        strcpy(name, vertex_name.c_str());
        type = vertex_type;
        weight = vertex_weight;
        inDegree = vertex_in_degree;
        outDegree = vertex_out_degree;
    }
};

//逻辑顶点数组？Logical Vertex Array
struct stinger_vertices
{
    p_int max_vertices;                        // 记录当前有效的顶点数目
    struct stinger_vertex vertices[VERTEX_NUM];
};


//边类型数组，每一个stinger_etype_array的对象应该对应一个边的类型
struct stinger_etype_array
{
    p_int length;         //边类型数组的长度
    p_int high;	        //边类型数组的High water mark
    pmem::obj::persistent_ptr<stinger_eb> eb_ptrs[EDGE_NUM_PER_TYPE];
};

struct stinger {
	struct stinger_vertices logical_vertex_array;
    struct stinger_etype_array etype_array[ETYPE_NUM];
    p_int max_etype_num;
    p_int max_vtype_num;
    pmem::obj::string vertex_type_map[VTYPE_NUM];
    pmem::obj::string edge_type_map[ETYPE_NUM];
    pmem::obj::persistent_ptr<hashmap> mapper = nullptr;

};

extern pmem::obj::pool<stinger> pop;
extern pmem::obj::persistent_ptr<stinger> stinger_root;


#endif